import {ref, watch} from 'vue';

/**
 * 双向绑定组合函数
 * @author  wsj
 * @date    2020/10/19 9:21
 */

/*
issue: 为什么要在useModel里多维护一个ref, 而不直接用props传递下来的？

答：为了防止不用v-model去绑定<Input>, 然后组件就没有办法输入任何值...
emmm... 为什么会不用v-model呢？ 这需求不叫奇葩... 但如果你要写个搜索框, 你不会用v-model去绑定输入框的内容, 你只会监听enter事件, 只要enter得到的文本, 比如Element的输入框就是这样
So 我们这里的数据其实看似是受父组件控制的, 其实是自控的, 不管用户有没有用v-model监听, input的值改变了都会改变model.value的值, 并且会向父组件触发update:modelValue事件 (详见useModel)
*/
export function useModel<T>(
  getter: () => T,
  emitter: (val: T) => void,
  config?: {
    autoEmit?: boolean | undefined,
    autoWatch?: boolean | undefined,
    onChange?: (newVal: T, oldVal: T) => void,
  }
) {

  const state = ref(getter()) as { value: T }
  config = config || {}

  if (config.autoWatch !== false) {
    watch(getter, (val: T) => {
      if (val != state.value) {
        if (config!.onChange) {
          config!.onChange(val, state.value)
        }
        state.value = val
      }
    })
  }

  return {
    get value() {
      return state.value
    },
    set value(val: T) {
      state.value = val
      if (config!.autoEmit !== false) {
        emitter((val))
      }
    }
  }
}
